Skip to content

[Payment due @mkhutornyi] Add ask Concierge screen - #100552

Open
rushatgabhane wants to merge 188 commits into
Expensify:mainfrom
rushatgabhane:concierge-ask-design
Open

rushatgabhane wants to merge 188 commits into
Expensify:mainfrom
rushatgabhane:concierge-ask-design

Conversation

@rushatgabhane

@rushatgabhane rushatgabhane commented Sep 7, 2026 •

Copy link
Copy Markdown
Member

Explanation of Change

Builds the Ask Concierge screen from the Figma design in the main Concierge DM: a centered welcome empty state, a chat history toggle that expands and collapses the earlier conversation, and a Your personal AI assistant subtitle plus a New chat button in question threads. It also removes the conciergeRespondInThread beta, so Concierge answers every question from the main DM in its own thread, including a message with several attachments. This needs https://github.com/Expensify/Web-Expensify/pull/57207 deployed first.

Fixed Issues

For #94503
PROPOSAL:

Tests

  1. Open the Concierge chat from the Inbox.
  2. Verify the header reads Concierge with the subtitle Your personal AI assistant, and the composer placeholder is How much did I spend last month?.
  3. Verify the chat shows the Concierge bot illustration, Ask me anything!, and the supporting copy. On a wide screen, verify the welcome and the composer are centered together. On a small screen (mobile), verify the welcome is centered above a composer docked at the bottom.
  4. Press View chat history, verify the earlier conversation appears with Ask a new question above the composer, then press Hide chat history and verify it collapses again.
  5. Ask a question, open the thread, and verify the header shows a New chat button that returns you to the Concierge chat in its welcome state.
  6. In the Concierge chat, click + > Add attachment, pick two images, type What are these? and send. Verify one message shows both images, a thread opens off it, Concierge replies once in the thread.
  7. Sign up a new account and pick Track expenses for my business in onboarding. Open the Concierge chat from the Inbox and verify it shows Ask me anything! with View chat history. Press View chat history and verify the onboarding tasks appear.
  • Verify that no errors appear in the JS console

Offline tests

Same as tests. The welcome state and the history toggle both read data already in Onyx, so they render offline; only expanding history beyond the cached page needs a connection.

QA Steps

Preconditions: three test accounts:

  • an account that has messaged Concierge before
  • a brand-new account with no onboarding tasks, so the Concierge chat is empty
  • a brand-new account with onboarding tasks
  1. Welcome screen
    1. Open Inbox > Concierge.
    2. Verify the header shows Concierge with the subtitle Your personal AI assistant.
    3. Verify the chat shows the Concierge illustration, Ask me anything!, Concierge can answer questions, update expenses, and more. and a View chat history button.
    4. On a wide screen, verify the welcome and the composer are centered together. On mobile, verify the composer is docked at the bottom.
  2. History toggle
    1. Press View chat history. Verify the earlier conversation appears, Hide chat history shows, and Ask a new question appears above the composer.
    2. Press Hide chat history. Verify the chat returns to the welcome screen.
  3. Question opens a thread
    1. From the welcome screen, type a question and send it.
    2. Verify the app opens a new thread, Concierge replies there, and the header shows a New chat button.
    3. Press New chat. Verify you land on the Concierge chat in its welcome state.
  4. Several attachments
    1. In the Concierge chat, press + > Add attachment and pick two images. Type What are these? and send.
    2. Verify one message shows both images, a thread opens, and Concierge replies once in that thread.
  5. Task
    1. In the Concierge chat, send [] Buy milk.
    2. Verify the task appears, the history is expanded, and the button reads Hide chat history.
  6. New account
    1. Sign up with a new account and finish onboarding.
    2. Open Concierge and refresh.
    3. Verify the welcome screen shows with View chat history.
    4. Press View chat history. Verify the onboarding message and tasks are there.
  7. Unread message
    1. In the expanded history, hover a Concierge message and choose Mark as unread.
    2. Leave the chat, then open Concierge again.
    3. Verify the history is expanded and the message is visible, not hidden behind the welcome.
  8. Link to a message
    1. Open a link to a specific Concierge message, for example from a thread's parent link or a Search result.
    2. Verify the chat opens at that message with Hide chat history, not the welcome screen.
  9. Full-size composer
    1. With the history expanded, expand the composer to full size.
    2. Verify the composer's bottom border is fully visible.
    3. Repeat from the welcome screen.
  10. Another device
    1. Keep the Concierge welcome open on web.
    2. Send a question to Concierge from a phone signed in to the same account.
    3. Verify the web stays on the welcome screen with no flash of the message list.
  11. Offline
    1. Go offline and send a question from the welcome screen. Verify the thread opens.
    2. Go back to the Concierge chat. Verify it shows the welcome screen.
    3. Go online. Verify it stays on the welcome screen.
  12. Side panel and Search
    1. Open the Concierge side panel from any report header. Verify it still shows its own greeting and, when there's earlier history, a Show history button.
    2. Send a question in the side panel. Verify it switches to the new thread.
    3. Open Search and use Ask Concierge to ask another question. Verify it creates a new thread instead of posting into the previous one.
  • Verify that no errors appear in the JS console

PR Author Checklist

  • I linked the correct issue in the ### Fixed Issues section above
  • I wrote clear testing steps that cover the changes made in this PR
    • I added steps for local testing in the Tests section
    • I added steps for the expected offline behavior in the Offline steps section
    • I added steps for Staging and/or Production testing in the QA steps section
    • I added steps to cover failure scenarios (i.e. verify an input displays the correct error message if the entered data is not correct)
    • I turned off my network connection and tested it while offline to ensure it matches the expected behavior (i.e. verify the default avatar icon is displayed if app is offline)
    • I tested this PR with a High Traffic account against the staging or production API to ensure there are no regressions (e.g. long loading states that impact usability).
  • I included screenshots or videos for tests on all platforms
  • I ran the tests on all platforms & verified they passed on:
    • Android: Native
    • Android: mWeb Chrome
    • iOS: Native
    • iOS: mWeb Safari
    • MacOS: Chrome / Safari
  • I verified there are no console errors (if there's a console error not related to the PR, report it or open an issue for it to be fixed)
  • I followed proper code patterns (see Reviewing the code)
    • I verified that comments were added to code that is not self explanatory
    • I verified that any new or modified comments were clear, correct English, and explained "why" the code was doing something instead of only explaining "what" the code was doing.
    • I verified any copy / text that was added to the app is grammatically correct in English. It adheres to proper capitalization guidelines (note: only the first word of header/labels should be capitalized), and is either coming verbatim from figma or has been approved by marketing (in order to get marketing approval, ask the Bug Zero team member to add the Waiting for copy label to the issue)
  • If a new code pattern is added I verified it was agreed to be used by multiple Expensify engineers
  • I followed the guidelines as stated in the Review Guidelines
  • I tested other components that can be impacted by my changes (i.e. if the PR modifies a shared library or component like Avatar, I verified the components using Avatar are working as expected)
  • If a new CSS style is added I verified that:
    • A similar style doesn't already exist
    • The style can't be created with an existing StyleUtils function (i.e. StyleUtils.getBackgroundAndBorderStyle(theme.componentBG))
  • If new assets were added or existing ones were modified, I verified that:
    • The assets are optimized and compressed (for SVG files, run npm run compress-svg)
    • The assets load correctly across all supported platforms.
  • If the PR modifies code that runs when editing or sending messages, I tested and verified there is no unexpected behavior for all supported markdown - URLs, single line code, code blocks, quotes, headings, bold, strikethrough, and italic.
  • If the PR modifies a generic component, I tested and verified that those changes do not break usages of that component in the rest of the App (i.e. if a shared library or component like Avatar is modified, I verified that Avatar is working as expected in all cases)
  • If the PR modifies a component related to any of the existing Storybook stories, I tested and verified all stories for that component are still working as expected.
  • If the PR modifies a component or page that can be accessed by a direct deeplink, I verified that the code functions as expected when the deeplink is used - from a logged in and logged out account.
  • If the PR modifies the UI (e.g. new buttons, new UI components, changing the padding/spacing/sizing, moving components, etc) or modifies the form input styles:
    • I verified that all the inputs inside a form are aligned with each other.
    • I added Design label and/or tagged @Expensify/design so the design team can review the changes.
  • If the PR adds or modifies the UI:
    • I asked an AI agent to review the changes for accessibility issues and addressed its findings.
    • I tested with a screen reader (VoiceOver on macOS) and verified all new/changed elements are reachable with a logical focus order.
    • I verified all new/changed elements have meaningful accessible names and roles.
    • I verified state changes are announced (e.g. checked/unchecked, expanded/collapsed, selected).
  • I added unit tests for any new feature or bug fix in this PR to help automatically prevent regressions in this user flow.
  • If the main branch was merged into this PR after a review, I tested again and verified the outcome was still expected according to the Test steps.

Screenshots/Videos

Android: Native
Android: mWeb Chrome
iOS: Native
iOS: mWeb Safari
MacOS: Chrome / Safari
Screen.Recording.2026-10-02.at.15.16.02.mov

Old stuff

image
Screen.Recording.2026-09-14.at.06.10.11.mov

@melvin-bot

melvin-bot Bot commented Sep 7, 2026

Copy link
Copy Markdown

Hey, I noticed you changed src/languages/en.ts in a PR from a fork. For security reasons, translations are not generated automatically for PRs from forks.

If you want to automatically generate translations for other locales, an Expensify employee will have to:

  1. Look at the code and make sure there are no malicious changes.
  2. Run the Generate static translations GitHub workflow. If you have write access and the K2 extension, you can simply click: [this button]

Alternatively, if you are an external contributor, you can run the translation script locally with your own OpenAI API key. To learn more, try running:

npx bun ./scripts/generateTranslations.ts --help

Typically, you'd want to translate only what you changed by running npx bun ./scripts/generateTranslations.ts --compare-ref main

@codecov

codecov Bot commented Sep 7, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Looks like you've decreased code coverage for some files. Please write tests to increase, or at least maintain, the existing level of code coverage. See our documentation here for how to interpret this table.

Files with missing lines Coverage Δ
src/App.tsx 100.00% <ø> (ø)
src/CONST/index.ts 95.90% <ø> (ø)
...components/Search/SearchRouter/useAskConcierge.tsx 97.91% <100.00%> (+0.09%) ⬆️
src/hooks/useConciergeAskState.ts 100.00% <100.00%> (ø)
src/hooks/useIsConciergeInboxDM.ts 100.00% <100.00%> (ø)
src/hooks/useReportActionsListModel.ts 100.00% <100.00%> (ø)
src/hooks/useReportActionsVisibility.ts 96.36% <100.00%> (-0.25%) ⬇️
src/hooks/useShouldSuppressConciergeIndicators.tsx 100.00% <100.00%> (ø)
src/libs/ReportUtils.ts 90.07% <100.00%> (+0.07%) ⬆️
src/libs/actions/Report/index.ts 75.67% <100.00%> (+0.73%) ⬆️
... and 19 more
... and 8 files with indirect coverage changes

@rushatgabhane

Copy link
Copy Markdown
Member Author

@mkhutornyi next PR that you can start reviewing

@rushatgabhane

Copy link
Copy Markdown
Member Author

thanks for the qa steps @mkhutornyi

@rushatgabhane

Copy link
Copy Markdown
Member Author

hey @puneetlath can you please trigger web and mobile build for this PR? we want to send this to QA before merging

@github-actions

Copy link
Copy Markdown
Contributor

🚧 shawnborton has triggered a test Expensify/App build. You can view the workflow run here.

@github-actions

Copy link
Copy Markdown
Contributor

🧪🧪 Use the links below to test this adhoc build on Android, iOS, and Web. Happy testing! 🧪🧪
Built from App PR #100552 with the pinned Mobile-Expensify submodule.

Android 🤖 iOS 🍎
❌ FAILED ❌ https://ad-hoc-expensify-cash.s3.us-east-1.amazonaws.com/rock-artifacts/ad-hoc/rock-ios-device-AdHoc-779dd28d-18b639c-3900d4f21522f5208cf8c84121872bed3c7ac0af/index.html
The QR code can't be generated, because the Android build failed iOS
Web 🕸️
https://100552.pr-testing.expensify.com
Web

👀 View the workflow run that generated this build 👀

# Conflicts:
#	src/hooks/useConciergeSidePanelReportActions.ts
#	src/pages/inbox/ConciergeSessionContext.tsx
@m-natarajan

Copy link
Copy Markdown

@rushatgabhane Its a pass in Web, waiting for the validation in iOS, noticed that when selecting "Hide chat history", an empty space remains below the composer.

Grabando.179.mp4

@rushatgabhane

rushatgabhane commented Oct 27, 2026 •

Copy link
Copy Markdown
Member Author

noticed that when selecting "Hide chat history", an empty space remains below the composer

heyy @m-natarajan, for web wide screen it is expected. the compose will be centered now

image

@m-natarajan

Copy link
Copy Markdown

Passed in iOS as well, Step 3 - The drop down arrow in Concierge thread is partially overlapped with the "New chat" button

Concierge.8-12.mp4
Concierge.1-7.mp4

@rushatgabhane

Copy link
Copy Markdown
Member Author

Fixed

image

@rushatgabhane

Copy link
Copy Markdown
Member Author

@puneetlath let's merge it?

Comment thread src/hooks/useIsAskConciergeChat.ts Outdated
import useOnyx from './useOnyx';

/** Whether the report is the Concierge chat in the Inbox */
function useIsAskConciergeChat(reportID: string | undefined): boolean {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it not possible to ask concierge questions from the side panel? And the purpose of this hook is to know both:

  1. whether this is the concierge DM (not a thread or different convo with Concierge)
  2. in the main pain in the inbox

Is that right? If so, I find this name a bit confusing. What about:

Suggested change
function useIsAskConciergeChat(reportID: string | undefined): boolean {
function useIsConciergeInboxDM(reportID: string | undefined): boolean {

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@MelvinBot please rename and merge main

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the sidepanel check will be removed in next PR

so the name would make more sense then

but i don't mind renaming it until then

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I renamed useIsAskConciergeChat to useIsConciergeInboxDM and merged main. Both are pushed.

  • Rename (77f8c3a): I renamed the file and the function, and the isAskConciergeChat variables in useConciergeAskState.ts and ComposerInput.tsx to isConciergeInboxDM.
  • Merge (c2825c9): Two conflicts, both in imports:
    • ReportActionsList.tsx: I kept this PR's imports and added CollapsedSystemMessages from main.
    • ReportActionsListTest.tsx: I kept ConciergeChatHistoryContext, which this PR renamed from ConciergeSessionContext, and added main's new ActionListContext and CollapsedSystemMessages imports.

npm run typecheck, lint on the changed files, and 4 related Jest suites (54 tests) pass.

@rushatgabhane

Copy link
Copy Markdown
Member Author

@MelvinBot fix conflicts and merge main

@melvin-bot

melvin-bot Bot commented Oct 28, 2026

Copy link
Copy Markdown

⚠️ MelvinBot couldn't start on that request — a transient infrastructure error stopped me before I began. Please try again in a moment. If it keeps happening, post in #melvinbot-ai.

MelvinBot and others added 2 commits October 28, 2026 20:27
Co-authored-by: Rushat Gabhane <[email protected]>

# Conflicts:
#	src/pages/inbox/report/ReportActionsList.tsx
#	tests/ui/ReportActionsListTest.tsx
puneetlath
puneetlath previously approved these changes Oct 28, 2026

@puneetlath puneetlath left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@rushatgabhane conflicts again unfortunately.

@rushatgabhane

Copy link
Copy Markdown
Member Author

@MelvinBot fix conflicts please

Co-authored-by: Rushat Gabhane <[email protected]>

# Conflicts:
#	src/pages/inbox/report/ReportActionCompose/ComposerInput.tsx
@MelvinBot

Copy link
Copy Markdown
Contributor

I fixed the merge conflicts. I merged the latest main into this branch and pushed the result (5f6396b).

There was one conflict, in ComposerInput.tsx. This PR's isConciergeInboxDM and placeholder lines sat next to the new shouldSkipAutoFocus line from main, so I kept both.

npm run typecheck, lint on the file, and 4 related Jest suites (53 tests) pass.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants